package com.hifar.sso.controller;

import com.hifar.abi.base.utils.AuthCfgUtils;
import com.hifar.fw.json.JsonUtils;
import com.hifar.fw.utils.jwt.JwtUtils;
import com.hifar.fw.utils.lang.StringUtils;
import com.hifar.plat.baseModal.secretstrategy.pojo.SysPersonsecretDatasecretRelation;
import com.hifar.plat.baseModal.secretstrategy.service.ISysPersonsecretDatasecretRelationService;
import com.hifar.plat.dept.pojo.BaseOrgDeptPlat;
import com.hifar.plat.dept.service.IBaseOrgDeptPlatService;
import com.hifar.plat.user.pojo.BaseOrgUserPlat;
import com.hifar.plat.user.service.IBaseOrgUserService;
import com.hifar.sso.model.*;
import com.hifar.sso.service.SSOAuthService;
import com.hifar.sso.util.SSOConstants;
import com.hifar.sys.BusiResponse;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * SSO认证控制器
 *
 * @author system
 * @since 1.0.0
 */
@RestController
@RequestMapping("/api/busi/sso")
@CrossOrigin(origins = "*")
public class SSOAuthController {

    private static final Logger logger = LoggerFactory.getLogger(SSOAuthController.class);

    @Value("${sys-config.env:SM}")
    private String sysEnv;

    @Autowired
    private SSOAuthService ssoAuthService;
    @Autowired
    private IBaseOrgUserService baseOrgUserService;
    @Autowired
    private ISysPersonsecretDatasecretRelationService sysPersonsecretDatasecretRelationService;
    @Autowired
    private IBaseOrgDeptPlatService IBaseOrgDeptPlatService;


    /**
     * 用户登录API（RESTful接口）
     *
     * @param request 登录请求
     * @return 登录响应
     */
    @PostMapping("/api/login")
    public ResponseEntity<SSOResponse> login(@RequestBody SSORequest request) {
        try {
            logger.info("用户登录请求，用户名: {}", request.getUsername());

            SSOResponse response = ssoAuthService.authenticate(request);

            if (response.isSuccess()) {
                logger.info("用户登录成功，用户ID: {}", response.getUser().getUserId());
            } else {
                logger.warn("用户登录失败，用户名: {}, 错误: {}", request.getUsername(), response.getMessage());
            }

            return ResponseEntity.ok(response);

        } catch (Exception e) {
            logger.error("用户登录异常", e);
            return ResponseEntity.ok(SSOResponse.error(500, "登录服务异常"));
        }
    }

    /**
     * 授权端点
     *
     * @param clientId 客户端ID
     * @param responseType 响应类型
     * @param redirectUri 重定向URI
     * @param scope 作用域
     * @param state 状态参数
     * @param request HTTP请求
     * @param response HTTP响应
     */
    @GetMapping("/authorize")
    public void authorize(
            @RequestParam("client_id") String clientId,
            @RequestParam("response_type") String responseType,
            @RequestParam("redirect_uri") String redirectUri,
            @RequestParam(value = "scope", required = false) String scope,
            @RequestParam(value = "state", required = false) String state,
            HttpServletRequest request,
            HttpServletResponse response) throws IOException {

        try {
            logger.info("授权请求，客户端ID: {}, 响应类型: {}", clientId, responseType);

            // 检查响应类型
            if (!SSOConstants.RESPONSE_TYPE_CODE.equals(responseType)) {
                redirectToError(response, redirectUri, SSOConstants.ERROR_INVALID_REQUEST,
                        "不支持的响应类型", state);
                return;
            }

            // 检查用户是否已登录
            String sessionId = getSessionId(request);
            if (sessionId == null) {
                // 重定向到登录页面
                redirectToLogin(request, response, clientId, responseType, redirectUri, scope, state);
                return;
            }

            // 生成授权码
            SSORequest ssoRequest = new SSORequest();
            ssoRequest.setClientId(clientId);
            ssoRequest.setRedirectUri(redirectUri);
            ssoRequest.setScope(scope);
            ssoRequest.setState(state);
            ssoRequest.setClientSecret(clientId);
            String code = ssoAuthService.generateAuthorizationCode(ssoRequest);

            // 重定向到客户端
            String redirectUrl = redirectUri + "?code=" + code;
            if (state != null) {
                redirectUrl += "&state=" + state;
            }

            response.sendRedirect(redirectUrl);

        } catch (Exception e) {
            logger.error("授权处理异常", e);
            redirectToError(response, redirectUri, SSOConstants.ERROR_SERVER_ERROR,
                    "授权服务异常", state);
        }
    }

    /**
     * 令牌端点
     *
     * @param grantType 授权类型
     * @param code 授权码
     * @param redirectUri 重定向URI
     * @param clientId 客户端ID
     * @param clientSecret 客户端密钥
     * @param username 用户名
     * @param password 密码
     * @param refreshToken 刷新令牌
     * @return 令牌响应
     */
    @PostMapping("/token")
    public ResponseEntity<SSOResponse> token(
            @RequestParam("grant_type") String grantType,
            @RequestParam(value = "code", required = false) String code,
            @RequestParam(value = "redirect_uri", required = false) String redirectUri,
            @RequestParam("client_id") String clientId,
            @RequestParam("client_secret") String clientSecret,
            @RequestParam(value = "username", required = false) String username,
            @RequestParam(value = "password", required = false) String password,
            @RequestParam(value = "refresh_token", required = false) String refreshToken) {

        try {
            logger.info("令牌请求，授权类型: {}, 客户端ID: {}", grantType, clientId);

            SSOResponse response;

            switch (grantType) {
                case SSOConstants.GRANT_TYPE_AUTHORIZATION_CODE:
                    response = handleAuthorizationCodeGrant(code, redirectUri, clientId, clientSecret);
                    break;
                case SSOConstants.GRANT_TYPE_PASSWORD:
                    response = handlePasswordGrant(username, password, clientId, clientSecret);
                    break;
                case SSOConstants.GRANT_TYPE_REFRESH_TOKEN:
                    response = handleRefreshTokenGrant(refreshToken, clientId, clientSecret);
                    break;
                default:
                    response = SSOResponse.error(400, "不支持的授权类型",
                            SSOConstants.ERROR_UNSUPPORTED_GRANT_TYPE, "不支持的授权类型");
            }

            return ResponseEntity.ok(response);

        } catch (Exception e) {
            logger.error("令牌处理异常", e);
            return ResponseEntity.ok(SSOResponse.error(500, "令牌服务异常"));
        }
    }

    /**
     * 用户信息端点
     *
     * @param request HTTP请求
     * @return 用户信息
     */
    @GetMapping("/userinfo")
    public ResponseEntity<SSOResponse> userinfo(HttpServletRequest request) {
        try {
            String accessToken = getAccessTokenFromRequest(request);
            if (accessToken == null) {
                return ResponseEntity.ok(SSOResponse.error(401, "缺少访问令牌"));
            }

            SSOUser user = ssoAuthService.validateToken(accessToken);
            if (user == null) {
                return ResponseEntity.ok(SSOResponse.error(401, "无效的访问令牌"));
            }

            SSOResponse response = SSOResponse.success("获取用户信息成功");
            response.setUser(user);

            return ResponseEntity.ok(response);

        } catch (Exception e) {
            logger.error("获取用户信息异常", e);
            return ResponseEntity.ok(SSOResponse.error(500, "获取用户信息异常"));
        }
    }

    /**
     * 撤销令牌端点
     *
     * @param accessToken 访问令牌
     * @return 撤销结果
     */
    @PostMapping("/revoke")
    public ResponseEntity<SSOResponse> revoke(@RequestParam("access_token") String accessToken) {
        try {
            logger.info("撤销令牌请求: {}", accessToken);

            boolean success = ssoAuthService.revokeToken(accessToken);

            if (success) {
                return ResponseEntity.ok(SSOResponse.success("令牌撤销成功"));
            } else {
                return ResponseEntity.ok(SSOResponse.error(400, "令牌撤销失败"));
            }

        } catch (Exception e) {
            logger.error("撤销令牌异常", e);
            return ResponseEntity.ok(SSOResponse.error(500, "撤销令牌异常"));
        }
    }

    /**
     * SSO回调接口
     *
     * @param request 回调请求参数
     * @return 登录结果
     */
    @PostMapping("/api/callback")
    public BusiResponse<CallbackResponse> callback(@RequestBody CallbackRequest request) {
        try {
            logger.info("SSO回调请求: {}", request);

            // 参数验证
            if (request.getCode() == null || request.getCode().trim().isEmpty()) {
                logger.error("授权码参数为空");
                return BusiResponse.error("授权码不能为空");
            }
            if (request.getClientId() == null || request.getClientId().trim().isEmpty()) {
                logger.error("客户端ID参数为空");
                return BusiResponse.error("客户端ID参数为空");
            }

            // 验证授权码
           /* SSOToken token = ssoAuthService.getTokenByCode(request.getCode(), request.getClientId(), request.getRedirectUri());
            if (token == null) {
                logger.error("无效的授权码: {}, 客户端ID: {}", request.getCode(), request.getClientId());
                return ResponseEntity.ok(SSOResponse.error(400, "无效的授权码"));
            }

            // 获取用户信息
            SSOUser user = ssoAuthService.getUserById(token.getUserId());
            if (user == null) {
                return ResponseEntity.ok(SSOResponse.error(400, "用户不存在"));
            }*/
            String username = request.getUsername();
            BaseOrgUserPlat baseOrgUserPlat = baseOrgUserService.queryByUserCode(username);
            String personKey = StringUtils.trimNull(baseOrgUserPlat.getSecretLevel());
            List<SysPersonsecretDatasecretRelation> dataSecretRelationList = sysPersonsecretDatasecretRelationService.lambdaQuery()
                .eq(SysPersonsecretDatasecretRelation::getPersonSecretKey, personKey)
                .eq(SysPersonsecretDatasecretRelation::getDelFlag, 0)
                .list();
            Set<String> dataSecretLevels = dataSecretRelationList.stream()
                .map(item -> StringUtils.trimNull(item.getDataSecretKey()))
                .collect(Collectors.toSet());

            long tm = System.currentTimeMillis();
            Map<String, Object> sessionMap = new HashMap<>();
            long duration = AuthCfgUtils.getSessionTimeout();
            sessionMap.put("tenantId", baseOrgUserPlat.getTenantId());
            sessionMap.put("userId", baseOrgUserPlat.getId());
            sessionMap.put("idName", baseOrgUserPlat.getIdName());
            sessionMap.put("mobile", baseOrgUserPlat.getMobile());
            sessionMap.put("iat", tm);
            sessionMap.put("exp", tm + duration);
            sessionMap.put("secretLevel", baseOrgUserPlat.getSecretLevel());
            sessionMap.put("dataSecretLevel", String.join(",", dataSecretLevels));
            sessionMap.put("userType", baseOrgUserPlat.getUserType());
            sessionMap.put("deptId", baseOrgUserPlat.getDeptId());


            String sessionStr = JsonUtils.toJson(sessionMap);
            String jwtToken = JwtUtils.createHS256Token(sessionStr, AuthCfgUtils.getTokenKey());

            String deptId = baseOrgUserPlat.getDeptId();
            BaseOrgDeptPlat baseOrgDeptPlat = new BaseOrgDeptPlat();
            if (StringUtils.isNotBlank(deptId)) {
                baseOrgDeptPlat = IBaseOrgDeptPlatService.getById(deptId);
            }
            CallbackResponse callbackResponse = new CallbackResponse();
            callbackResponse.setToken(jwtToken);
            callbackResponse.setUserInfo(baseOrgUserPlat);
            callbackResponse.setDeptInfo(baseOrgDeptPlat);
            Map<String, Object> ext = new HashMap<>(2);

            // 平台登陆通过
            Subject subject = SecurityUtils.getSubject();
            if (!subject.isAuthenticated()) {
                UsernamePasswordToken token = new UsernamePasswordToken(username, "123123");
                // 执行登陆操作
                subject.login(token);
            }
            if (null != subject.getSession()) {
                String sessionId = (String) subject.getSession().getId();
                ext.put("sessionId", sessionId);
            }
            BusiResponse response = new BusiResponse();
            ext.put("systemConfigEnv", sysEnv);
            response.setExt(ext);
            response.setData(callbackResponse);
            return response;
        } catch (Exception e) {
            logger.error("SSO回调处理异常", e);
            return BusiResponse.error("SSO回调处理异常");
        }
    }

    /**
     * 单点登出端点
     *
     * @param userId 用户ID
     * @return 登出结果
     */
    @PostMapping("/logout")
    public ResponseEntity<SSOResponse> logout(@RequestParam("user_id") String userId) {
        try {
            logger.info("用户登出请求，用户ID: {}", userId);

            boolean success = ssoAuthService.logout(userId);

            if (success) {
                return ResponseEntity.ok(SSOResponse.success("登出成功"));
            } else {
                return ResponseEntity.ok(SSOResponse.error(400, "登出失败"));
            }

        } catch (Exception e) {
            logger.error("用户登出异常", e);
            return ResponseEntity.ok(SSOResponse.error(500, "登出异常"));
        }
    }

    /**
     * 处理授权码授权
     */
    private SSOResponse handleAuthorizationCodeGrant(String code, String redirectUri,
            String clientId, String clientSecret) {
        try {
            SSOToken token = ssoAuthService.getTokenByCode(code, clientId, redirectUri);
            return SSOResponse.success("获取令牌成功", token.getUserId(), token);
        } catch (Exception e) {
            logger.error("处理授权码授权异常", e);
            return SSOResponse.error(400, "获取令牌失败",
                    SSOConstants.ERROR_INVALID_GRANT, "无效的授权码");
        }
    }

    /**
     * 处理密码授权
     */
    private SSOResponse handlePasswordGrant(String username, String password,
            String clientId, String clientSecret) {
        try {
            SSORequest request = new SSORequest(username, password);
            request.setClientId(clientId);
            request.setClientSecret(clientSecret);

            return ssoAuthService.authenticate(request);
        } catch (Exception e) {
            logger.error("处理密码授权异常", e);
            return SSOResponse.error(400, "认证失败",
                    SSOConstants.ERROR_INVALID_GRANT, "用户名或密码错误");
        }
    }

    /**
     * 处理刷新令牌授权
     */
    private SSOResponse handleRefreshTokenGrant(String refreshToken, String clientId, String clientSecret) {
        try {
            SSOToken token = ssoAuthService.refreshToken(refreshToken, clientId);
            return SSOResponse.success("令牌刷新成功", token.getUserId(), token);
        } catch (Exception e) {
            logger.error("处理刷新令牌授权异常", e);
            return SSOResponse.error(400, "刷新令牌失败",
                    SSOConstants.ERROR_INVALID_GRANT, "无效的刷新令牌");
        }
    }

    /**
     * 重定向到错误页面
     */
    private void redirectToError(HttpServletResponse response, String redirectUri,
            String error, String errorDescription, String state) throws IOException {
        String errorUrl = redirectUri + "?error=" + error + "&error_description=" + errorDescription;
        if (state != null) {
            errorUrl += "&state=" + state;
        }
        response.sendRedirect(errorUrl);
    }

    /**
     * 重定向到登录页面
     */
    private void redirectToLogin(HttpServletRequest request, HttpServletResponse response,
            String clientId, String responseType, String redirectUri, String scope, String state)
            throws IOException {
        // TODO: 实现登录页面重定向逻辑
        String loginUrl = "/login?client_id=" + clientId +
                "&response_type=" + responseType +
                "&redirect_uri=" + redirectUri;
        if (scope != null) {
            loginUrl += "&scope=" + scope;
        }
        if (state != null) {
            loginUrl += "&state=" + state;
        }
        response.sendRedirect(loginUrl);
    }

    /**
     * 从请求中获取会话ID
     */
    private String getSessionId(HttpServletRequest request) {
        // TODO: 实现会话ID获取逻辑
        return request.getSession().getId();
    }

    /**
     * 从请求中获取访问令牌
     */
    private String getAccessTokenFromRequest(HttpServletRequest request) {
        String authHeader = request.getHeader(SSOConstants.HEADER_AUTHORIZATION);
        if (authHeader != null && authHeader.startsWith(SSOConstants.TOKEN_TYPE_BEARER + " ")) {
            return authHeader.substring(7);
        }
        return null;
    }
}
